package org.swift.mashup.engine.model;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.axiom.attachments.utils.IOUtils;
import org.apache.commons.io.FileUtils;
import org.swift.mashup.engine.api.ScriptEngine;
import org.swift.mashup.engine.api.ScriptEngineException;
import org.swift.mashup.engine.api.ScriptEngineProvider;

public class ScriptEngineActivity implements Activity {
	private static final String FROM_PARAMETER_NAME = "source";
	private static final String RESULTS_PARAMETER_NAME = "result";

	private final ScriptEngineProvider scriptEngineProvider;
	private final String script;

	public ScriptEngineActivity(ScriptEngineProvider scriptEnginePool,
			String script) {
		this.script = script;
		this.scriptEngineProvider = scriptEnginePool;
	}

	public ActivityResultComponent doActivity(ActivityContext context,
			Map<String, ? extends Object> parameters) throws ActivityException {
		final ScriptEngine engine = getEngine();
		String value = null, parameterName = null;
		try {
			if (context != null && context.getSize() > 0) {
				parameterName = FROM_PARAMETER_NAME;
				engine.setParameter(parameterName, new String(context
					.getBytes()));
			}
			for (Entry<String, ? extends Object> entry : parameters.entrySet()) {
				parameterName = entry.getKey();
				value = toString(entry.getValue());
				engine.setParameter(parameterName, value);
			}
			engine.runCommand(script);
			return new ActivityResultItem(new String(engine.getParameter(
				RESULTS_PARAMETER_NAME).getBytes()));
		} catch (ScriptEngineException see) {
			throw new ActivityException("An error occurred with the "
					+ "script engine instance.", see);
		} catch (IOException e) {
			throw new ActivityException("Failed to read the parameter \""
					+ parameterName + "\" into the activity.", e);
		} finally {
			try {
				engine.close();
			} catch (Exception e) {
				throw new ActivityException("Failed to close script engine.", e);
			}
		}
	}

	protected ScriptEngine getEngine() throws ActivityException {
		try {
			return (ScriptEngine) scriptEngineProvider.getScriptEngine();
		} catch (Exception cce) {
			throw new ActivityException("Unable to get script "
					+ "engine from the resource pool", cce);
		}
	}

	private String toString(final Object object) throws IOException,
			NotSupportedActivityException {
		if (object instanceof String) {
			return (String) object;
		}
		if (object instanceof byte[]) {
			return new String((byte[]) object);
		}
		if (object instanceof File) {
			return FileUtils.readFileToString((File) object);
		}
		if (object instanceof InputStream) {
			return new String(IOUtils
				.getStreamAsByteArray((InputStream) object));
		}
		throw new NotSupportedActivityException(object.getClass().toString());
	}
}
